package vip.xiaonuo.client.modular.wxuser.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.freewayso.image.combiner.ImageCombiner;
import com.freewayso.image.combiner.element.ImageElement;
import com.freewayso.image.combiner.enums.OutputFormat;
import com.freewayso.image.combiner.enums.ZoomMode;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;
import vip.xiaonuo.auth.core.util.StpClientUtil;
import vip.xiaonuo.biz.modular.user.entity.BizFzUser;
import vip.xiaonuo.biz.modular.user.service.BizFzUserService;
import vip.xiaonuo.client.modular.wxuser.entity.ClientUser;
import vip.xiaonuo.client.modular.wxuser.enums.ClientUserStatusEnum;
import vip.xiaonuo.client.modular.wxuser.mapper.ClientUserMapper;
import vip.xiaonuo.client.modular.wxuser.param.*;
import vip.xiaonuo.client.modular.wxuser.service.ClientUserService;
import vip.xiaonuo.common.exception.CommonException;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;

@Slf4j
@Service
public class ClientUserServiceimpl extends ServiceImpl<ClientUserMapper, ClientUser> implements ClientUserService {

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private BizFzUserService fzUserService;

    @Override
    public String login(ClientUserLoginParam loginParam) {
        LambdaQueryWrapper<ClientUser> wrapper = new LambdaQueryWrapper<ClientUser>().eq(ClientUser::getPhone, loginParam.getPhone());
        ClientUser user = this.getOne(wrapper);//查询用户是否存在
        if (ObjectUtil.isNull(user)){
            throw new CommonException("用户不存在");
        }
        if (ObjectUtil.notEqual(user.getPassword(),loginParam.getPassword())){
            throw new CommonException("密码不正确");
        }
        if (ObjectUtil.equal(ClientUserStatusEnum.DISABLED.getValue(),user.getStatus())){
            throw new CommonException("账户已被封禁");
        }
        //利用sa-token完成登陆
        StpClientUtil.login(user.getId(), new SaLoginModel().setDevice("MINI").setExtra("id", user.getId()));
        // 缓存用户信息，此处使用TokenSession为了指定时间内无操作则自动下线
        StpClientUtil.getTokenSession().set("clientLoginUser", user);
        StpClientUtil.getSession().set("wxuser", JSONUtil.toJsonStr(user));
        return StpClientUtil.getTokenInfo().tokenValue;
    }

    @Override
    public ClientUser getUserInfo() {
        String userId = StpClientUtil.getLoginIdAsString();
        return this.getById(userId);
    }

    @Override
    public void add(ClientUserAddParam addParam) {
        ClientUser user = BeanUtil.copyProperties(addParam, ClientUser.class);
        LambdaQueryWrapper<ClientUser> clientUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        clientUserLambdaQueryWrapper.eq(ClientUser::getPhone, user.getPhone());
        ClientUser one = this.getOne(clientUserLambdaQueryWrapper);
        if (ObjectUtil.isNotNull(one)){
            throw new CommonException("手机号已被注册");
        }
        user.setStatus(ClientUserStatusEnum.ENABLE.getValue());
        this.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String wxMaLogin(WxMaLoginParam wxMaLoginParam) {
        try {
            // 通过code获取openid和session_key
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(wxMaLoginParam.getCode());
            String openid = sessionInfo.getOpenid();
            String sessionKey = sessionInfo.getSessionKey();

            log.info("微信小程序登录，openid: {}", openid);

            // 查询是否已有该openid的用户
            ClientUser existUser = this.getOne(new LambdaQueryWrapper<ClientUser>()
                    .eq(ClientUser::getOpenId, openid));

            // 用户不存在，则创建新用户
            if (existUser == null) {
                log.info("微信小程序用户不存在，创建新用户");
                existUser = new ClientUser();
                existUser.setOpenId(openid);
                existUser.setStatus(ClientUserStatusEnum.ENABLE.getValue());
                // 处理邀请码，解密获取邀请人ID
                if(StrUtil.isNotBlank(wxMaLoginParam.getInvitationUserId()) && !"undefined".equals(wxMaLoginParam.getInvitationUserId())) {
//                    try {
                        // 解密邀请码，获取原始用户ID
//                        String decryptedInviterId = CommonCryptogramUtil.doSm2Decrypt(wxMaLoginParam.getInvitationUserId());
                    // 检测邀请人是否存在
                    BizFzUser inviter = fzUserService.getById(wxMaLoginParam.getInvitationUserId());
                    if (inviter == null) {
                        log.warn("邀请人不存在，invitationId: {}", wxMaLoginParam.getInvitationUserId());
                        //throw new CommonException("邀请人不存在");
                    } else {
                        existUser.setInvitationUserId(wxMaLoginParam.getInvitationUserId());
                    }
//                    } catch (Exception e) {
//                        log.warn("邀请码解密失败: {}", e.getMessage());
//                        // 解密失败时不设置邀请人ID
//                    }
                }

                // 获取用户信息
                try {
                    // 获取用户基本信息
                    WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, null, null);
                    if (userInfo != null) {
                        existUser.setName(userInfo.getNickName());
                        existUser.setAvatar(userInfo.getAvatarUrl());
                        existUser.setSex(userInfo.getGender());
                    }

                    // 获取用户手机号
                    if (StrUtil.isNotBlank(wxMaLoginParam.getPhoneCode())) {
                        WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(wxMaLoginParam.getPhoneCode());
                        if (phoneInfo != null) {
                            existUser.setPhone(phoneInfo.getPhoneNumber());
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.warn("获取微信用户信息失败: {}", e.getMessage());
                }

                // 判断fz用户表中是否有相同的openid，且是普通用户，如果有则该用户为分销用户
                if (fzUserService.getOne(new LambdaQueryWrapper<BizFzUser>().eq(BizFzUser::getOpenId, openid)) != null) {
                    existUser.setUserType("fz");
                }

                this.save(existUser);
                log.info("微信小程序新用户创建成功，用户ID: {}", existUser.getId());
            } else {
                // 用户存在，更新用户信息
                log.info("微信小程序用户已存在，更新用户信息，用户ID: {}", existUser.getId());
                boolean needUpdate = false;

                if (StrUtil.isBlank(existUser.getOpenId())) {
                    existUser.setOpenId(openid);
                    needUpdate = true;
                }

                // 如果用户信息不完整，尝试获取
                if (StrUtil.isBlank(existUser.getPhone()) || StrUtil.isBlank(existUser.getName()) ||
                    StrUtil.isBlank(existUser.getAvatar()) || StrUtil.isBlank(existUser.getSex())) {
                    try {
                        WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionKey, null, null);
                        if (userInfo != null) {
                            if (StrUtil.isBlank(existUser.getName())) {
                                existUser.setName(userInfo.getNickName());
                                needUpdate = true;
                            }
                            if (StrUtil.isBlank(existUser.getAvatar())) {
                                existUser.setAvatar(userInfo.getAvatarUrl());
                                needUpdate = true;
                            }
                            if (StrUtil.isBlank(existUser.getSex())) {
                                existUser.setSex(userInfo.getGender());
                                needUpdate = true;
                            }
                        }

                        // 如果手机号为空，尝试获取
                        if (StrUtil.isBlank(existUser.getPhone()) && StrUtil.isNotBlank(wxMaLoginParam.getPhoneCode())) {
                            WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(wxMaLoginParam.getPhoneCode());
                            if (phoneInfo != null) {
                                existUser.setPhone(phoneInfo.getPhoneNumber());
                                needUpdate = true;
                            }
                        }
                    } catch (Exception e) {
                        log.warn("获取微信用户信息失败: {}", e.getMessage());
                    }
                }

                // 判断fz用户表中是否有相同的openid，且是普通用户，如果有则该用户为分销用户
                if (fzUserService.getOne(new LambdaQueryWrapper<BizFzUser>().eq(BizFzUser::getOpenId, openid)) != null
                    && existUser.getUserType().equals("normal")
                ) {
                    existUser.setUserType("fz");
                    needUpdate = true;
                }

                if (needUpdate) {
                    this.updateById(existUser);
                    log.info("微信小程序用户信息已更新");
                }
            }

            // 如果用户已禁用，则拒绝登录
            if (ObjectUtil.equal(ClientUserStatusEnum.DISABLED.getValue(), existUser.getStatus())) {
                throw new CommonException("账户已被封禁");
            }

            // 登录处理
            StpClientUtil.login(existUser.getId(), new SaLoginModel()
                    .setDevice("MINI")
                    .setExtra("id", existUser.getId())
                    .setExtra("openid", openid));

            // 缓存用户信息
            StpClientUtil.getTokenSession().set("clientLoginUser", existUser);
            StpClientUtil.getSession().set("wxuser", JSONUtil.toJsonStr(existUser));

            log.info("微信小程序用户登录成功，用户ID: {}", existUser.getId());
            return StpClientUtil.getTokenInfo().tokenValue;

        } catch (CommonException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("微信小程序登录失败", e);
            throw new CommonException("微信小程序登录失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindFzUser(ClientUserFzBindParam bindParam) {
        try {
            // 1. 获取当前登录用户
            String userId = StpClientUtil.getLoginIdAsString();
            ClientUser currentUser = this.getById(userId);
            if (currentUser == null) {
                throw new CommonException("当前用户不存在");
            }

            // 2. 查询分销账户是否存在
            LambdaQueryWrapper<BizFzUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(BizFzUser::getPhone, bindParam.getPhone())
                    .eq(BizFzUser::getPassword, bindParam.getPassword());
            BizFzUser fzUser = fzUserService.getOne(queryWrapper);

            if (fzUser == null) {
                throw new CommonException("分销商户账户不存在或密码错误");
            }

            // 3. 检查该分销账户是否已经绑定了其他用户的openid
            if (StrUtil.isNotBlank(fzUser.getOpenId())) {
                throw new CommonException("该分销账户已经绑定了其他微信用户");
            }

            // 4. 绑定分销账户的openid为当前用户的openid
            fzUser.setOpenId(currentUser.getOpenId());
            boolean updateResult = fzUserService.updateById(fzUser);

            if (!updateResult) {
                throw new CommonException("绑定分销账户失败");
            }

            // 5. 更新当前用户类型为fz
            currentUser.setUserType("fz");
            this.updateById(currentUser);

            log.info("用户成功绑定分销账户，用户ID: {}, 分销账户ID: {}", userId, fzUser.getId());
            return true;
        } catch (CommonException e) {
            throw e;
        } catch (Exception e) {
            log.error("绑定分销账户失败", e);
            throw new CommonException("绑定分销账户失败: " + e.getMessage());
        }
    }

    public String generateInvitationCode(String wxQrCode) throws Exception {
        String bgImageUrl = "https://picx.zhimg.com/80/v2-01ab10af38ca1dc536ade2e9ea62be74_720w.jpeg";
        //创建合成器（指定背景图和输出格式，整个图片的宽高和相关计算依赖于背景图，所以背景图的大小是个基准）
        ImageCombiner imageCombiner = new ImageCombiner(bgImageUrl, OutputFormat.JPEG);

        byte[] imageBytes = Base64Utils.decodeFromString(wxQrCode);
        BufferedImage image = ImgUtil.toImage(imageBytes);

        imageCombiner.addImageElement(image, 450, 520, 170, 170, ZoomMode.Width);
        // 执行合成
        // 创建一个BufferedImage对象用于合成图片
        BufferedImage combinedImage = imageCombiner.combine();

//        imageCombiner.save("d://image.jpg");

        // 将BufferedImage转换为字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(combinedImage, "png", byteArrayOutputStream);
        byte[] resultImageBytes = byteArrayOutputStream.toByteArray();

        // 将图片字节数组转换为Base64编码字符串
        String base64Result = Base64.getEncoder().encodeToString(resultImageBytes);
        return base64Result;
    }

    @Override
    public String generateInvitationCode2(String wxQrCode) throws Exception {
        String bgImageUrl = "https://picx.zhimg.com/80/v2-9a359393704f9135c31eb12ec7f68671_1440w.png";
        //创建合成器（指定背景图和输出格式，整个图片的宽高和相关计算依赖于背景图，所以背景图的大小是个基准）
        ImageCombiner imageCombiner = new ImageCombiner(bgImageUrl, OutputFormat.JPEG);

        byte[] imageBytes = Base64Utils.decodeFromString(wxQrCode);
        BufferedImage image = ImgUtil.toImage(imageBytes);

        imageCombiner.addImageElement(image, 980, 185, 300, 320, ZoomMode.Width);
        // 执行合成
        // 创建一个BufferedImage对象用于合成图片
        BufferedImage combinedImage = imageCombiner.combine();

//        imageCombiner.save("d://image.jpg");

        // 将BufferedImage转换为字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ImageIO.write(combinedImage, "png", byteArrayOutputStream);
        byte[] resultImageBytes = byteArrayOutputStream.toByteArray();

        // 将图片字节数组转换为Base64编码字符串
        String base64Result = Base64.getEncoder().encodeToString(resultImageBytes);
        return base64Result;
    }

    @Override
    public String generateMaQrCode(WxQrCodeParam wxQrCodeParam) {
//        String fzUserId = StpClientUtil.getLoginIdAsString();
//        BizFzUser fzUser = fzUserService.getById(fzUserId);
        try {
            // 设置默认值
            String scene = StrUtil.isBlank(wxQrCodeParam.getScene()) ? "a=1" : wxQrCodeParam.getScene();
            String page = StrUtil.isBlank(wxQrCodeParam.getPage()) ? "pages/index/index" : wxQrCodeParam.getPage();
            boolean checkPath = wxQrCodeParam.getCheckPath() == null ? true : wxQrCodeParam.getCheckPath();
            String envVersion = StrUtil.isBlank(wxQrCodeParam.getEnvVersion()) ? "release" : wxQrCodeParam.getEnvVersion();
            int width = wxQrCodeParam.getWidth() == null ? 430 : wxQrCodeParam.getWidth();
            boolean autoColor = wxQrCodeParam.getAutoColor() == null ? false : wxQrCodeParam.getAutoColor();
            boolean isHyaline = wxQrCodeParam.getIsHyaline() == null ? false : wxQrCodeParam.getIsHyaline();

            log.info("生成小程序码参数: scene={}, page={}, checkPath={}, envVersion={}, width={}, autoColor={}, isHyaline={}",
                    scene, page, checkPath, envVersion, width, autoColor, isHyaline);

            // 根据实际方法签名调整参数顺序:
            // createWxaCodeUnlimitBytes(String var1, String var2, boolean var3, String var4, int var5, boolean var6, WxMaCodeLineColor var7, boolean var8)
            // 推测参数对应关系:
            // var1=scene, var2=page, var3=checkPath, var4=envVersion, var5=width, var6=autoColor, var7=lineColor, var8=isHyaline
            byte[] qrCodeBytes = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(
                scene,      // 场景值
                page,       // 页面路径
                checkPath,  // 是否检查页面路径
                envVersion, // 环境版本
                width,      // 宽度
                autoColor,  // 自动配置线条颜色
                null,       // 线条颜色配置(null使用默认值)
                isHyaline   // 是否需要透明底色
            );

            // 将字节数组转为Base64字符串
            String base64QrCode = cn.hutool.core.codec.Base64.encode(qrCodeBytes);

            // 生成小程序base64的二维码太长了。。。注释掉不存库了，每次都通过接口生成
//            if (wxQrCodeParam.getType().equals("fz")) {
//                fzUser.setQrcode("data:image/png;base64," + base64QrCode);
//            } else {
//                fzUser.setQrcodeNormal("data:image/png;base64," + base64QrCode);
//            }
//            fzUserService.updateById(fzUser);

            // 添加Data URI前缀，便于直接在前端使用
            return "data:image/png;base64," + base64QrCode;

        } catch (WxErrorException e) {
            log.error("生成小程序码失败", e);
            throw new CommonException("生成小程序码失败: " + e.getMessage());
        }
    }

    @Override
    public String generateMaQrCode2(WxQrCodeParam wxQrCodeParam) throws Exception {
        String fzUserId = StpClientUtil.getLoginIdAsString();
        BizFzUser fzUser = fzUserService.getById(fzUserId);

        try {
            // 设置默认值
            String scene = StrUtil.isBlank(wxQrCodeParam.getScene()) ? "a=1" : wxQrCodeParam.getScene();
            String page = StrUtil.isBlank(wxQrCodeParam.getPage()) ? "pages/index/index" : wxQrCodeParam.getPage();
            boolean checkPath = wxQrCodeParam.getCheckPath() == null ? true : wxQrCodeParam.getCheckPath();
            String envVersion = StrUtil.isBlank(wxQrCodeParam.getEnvVersion()) ? "release" : wxQrCodeParam.getEnvVersion();
            int width = wxQrCodeParam.getWidth() == null ? 430 : wxQrCodeParam.getWidth();
            boolean autoColor = wxQrCodeParam.getAutoColor() == null ? false : wxQrCodeParam.getAutoColor();
            boolean isHyaline = wxQrCodeParam.getIsHyaline() == null ? false : wxQrCodeParam.getIsHyaline();

            log.info("生成小程序码参数: scene={}, page={}, checkPath={}, envVersion={}, width={}, autoColor={}, isHyaline={}",
                    scene, page, checkPath, envVersion, width, autoColor, isHyaline);

            // 根据实际方法签名调整参数顺序:
            // createWxaCodeUnlimitBytes(String var1, String var2, boolean var3, String var4, int var5, boolean var6, WxMaCodeLineColor var7, boolean var8)
            // 推测参数对应关系:
            // var1=scene, var2=page, var3=checkPath, var4=envVersion, var5=width, var6=autoColor, var7=lineColor, var8=isHyaline
            byte[] qrCodeBytes = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(
                    scene,      // 场景值
                    page,       // 页面路径
                    checkPath,  // 是否检查页面路径
                    envVersion, // 环境版本
                    width,      // 宽度
                    autoColor,  // 自动配置线条颜色
                    null,       // 线条颜色配置(null使用默认值)
                    isHyaline   // 是否需要透明底色
            );

            // 将字节数组转为Base64字符串
            String base64QrCode = cn.hutool.core.codec.Base64.encode(qrCodeBytes);

            // 生成小程序base64的二维码太长了。。。注释掉不存库了，每次都通过接口生成
//            if (wxQrCodeParam.getType().equals("fz")) {
//                fzUser.setQrcode("data:image/png;base64," + base64QrCode);
//            } else {
//                fzUser.setQrcodeNormal("data:image/png;base64," + base64QrCode);
//            }
//            fzUserService.updateById(fzUser);

            // 添加Data URI前缀，便于直接在前端使用
            if (fzUser.getFzRole().equals("WYCSJ") || fzUser.getFzRole().equals("WYCGS")) {
                return "data:image/png;base64," + generateInvitationCode2(base64QrCode);
            }
            return "data:image/png;base64," + generateInvitationCode(base64QrCode);

        } catch (WxErrorException e) {
            log.error("生成小程序码失败", e);
            throw new CommonException("生成小程序码失败: " + e.getMessage());
        }
    }
}
